﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CommandBase.h"
#include "GbmpUiPlatformCommandIds.h "

#include "IUiDocumentViewManager.h"

#include "IUiDocument.h"
#include "IDocument.h"
#include "UndoRedoUtils.h"
#include "IUserTransaction.h"
#include "ISelection.h"
#include "IActionManager.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "UiCommonDialog.h"

#include "IHighlights.h"
#include "GcmpCommandState.h"
#include "IPropertyWidget.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

//////////////////////////////////////////////////////////////////////////
class CmdUndo : public CommandBase
{
public:
    CmdUndo();
    ~CmdUndo();

public:
    virtual bool IsEnabled() const override;
    virtual bool IsVisible() const override;
    virtual gcmp::OwnerPtr<IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;
};

CmdUndo::CmdUndo()
    : CommandBase(ID_CMD_UNDO)
{
}

CmdUndo::~CmdUndo()
{

}

bool CmdUndo::IsEnabled() const
{
    if(!CommandBase::IsEnabled())
        return false;

    // Firstly, Undo cmd is only enabled in document evn
    if (!GcmpCommandState::IsInDocumentEnvironment())
    {
        return false;
    }

    IUiDocument* pUIDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    return  !IUserTransaction::IsInUserTransaction(pDoc) &&
            !pDoc->IsInTransactionUndo() && !pDoc->IsInTransactionRedo() && !pDoc->IsInTransactionRollback() &&
            UndoRedoUtils::CanUndo(pDoc);
}

bool CmdUndo::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

class UndoConfirm : public IUndoConfirm
{
public:
    virtual bool ConfirmToExecuteUndoWithoutRedoCapability(
        const std::wstring & undoName) override
    {
        std::wstringstream wss;
        wss << L"下列操作一旦撤消就不能再恢复：\n";
        wss << undoName << "\n";
        wss << L"是否继续执行“撤消”操作？";

        UiCommonDialog::ButtonType confirm = UiCommonDialog::ShowMessageBox(
            L"请确认", wss.str(), 
            (int32_t)UiCommonDialog::ButtonType::Yes | 
            (int32_t)UiCommonDialog::ButtonType::No);
        return UiCommonDialog::ButtonType::Yes == confirm;
    }
};

gcmp::OwnerPtr<IAction> CmdUndo::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocument* pUIDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // 取消当前Action
    IActionManager::Reset();
    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
    // DB层撤消操作
    UndoConfirm undoConfirm;

    //单步撤销
    UndoRedoUtils::Undo(pDoc, &undoConfirm);

    // UI层刷新
    pUIDoc->UpdateView();

    // no public api yet
    // UIDocUtil::UpdatePropertyPanel();

    IPropertyWidget* pPropertyWidget = IPropertyWidget::GetPropertyWidget();
    if(pPropertyWidget)
        pPropertyWidget->Refresh(false);

    return nullptr;
}

//////////////////////////////////////////////////////////////////////////
class CmdRedo : public CommandBase
{
public:
    CmdRedo();
    ~CmdRedo();

public:
    virtual bool IsEnabled() const override;
    virtual bool IsVisible() const override;
    virtual gcmp::OwnerPtr<IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;
};

CmdRedo::CmdRedo()
    : CommandBase(ID_CMD_REDO)
{
}

CmdRedo::~CmdRedo()
{

}

bool CmdRedo::IsEnabled() const
{
    if(!CommandBase::IsEnabled())
        return false;

    // Firstly, Redo cmd is only enabled in document evn
    if (!GcmpCommandState::IsInDocumentEnvironment())
    {
        return false;
    }

    IUiDocument* pUIDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    return  !IUserTransaction::IsInUserTransaction(pDoc) &&
        !pDoc->IsInTransactionUndo() && !pDoc->IsInTransactionRedo() && !pDoc->IsInTransactionRollback() &&
        UndoRedoUtils::CanRedo(pDoc);
}

bool CmdRedo::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<IAction> CmdRedo::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IUiDocument* pUIDoc = IUiDocumentViewManager::Get()->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, nullptr, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    // 取消当前Action
    IActionManager::Reset();
    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();

    std::vector<std::wstring> redoName = UndoRedoUtils::GetRedoNames(pDoc);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!redoName.empty(), L"Redo名字列表为空？",L"GDMPLab",L"2024-03-30");

    // 单步重做，DB层重做操作
    UndoRedoUtils::Redo(pDoc);

    // UI层刷新
    pUIDoc->UpdateView();

    // no public api yet
    // UIDocUtil::UpdatePropertyPanel();

    IPropertyWidget* pPropertyWidget = IPropertyWidget::GetPropertyWidget();
    if (pPropertyWidget)
        pPropertyWidget->Refresh(false);

    return nullptr;
}

REGISTER_GM_COMMAND(CmdUndo);
REGISTER_GM_COMMAND(CmdRedo);


